﻿using Sirenix.OdinInspector;
using Sirenix.Utilities;
using Sirenix.Utilities.Editor;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;

public class CreateConfig : IScriptableObject<CreateConfig>
{
    [LabelText("勾选进行编辑")]
    public bool IsCanEditor;

    [EnableIf("IsCanEditor")]
    [LabelText("常用类库配置")]
    [ListDrawerSettings(OnTitleBarGUI = "RefreshCSharpInfo", DraggableItems = false)]
    public List<CSharpInfo> CSharpInfoList = new List<CSharpInfo>()
    {
        new CSharpInfo()
        {
            IsNone = true, IsCSTypeInfo = false, AssemblieName = "Assembly-CSharp",
            CSTypeInfoList = new List<CSTypeInfo>()
            {
                new CSTypeInfo() {TypeName = "SerializeInter"},
                new CSTypeInfo() {TypeName = "SerializeNode"},
                new CSTypeInfo() {TypeName = "SerializeRoot"},
            }
        },
        new CSharpInfo()
        {
            IsNone = true, IsCSTypeInfo = false, AssemblieName = "UnityEngine.UI",
            CSTypeInfoList = new List<CSTypeInfo>()
            {
                new CSTypeInfo() {TypeName = "UnityEngine.UI.Button"},
                new CSTypeInfo() {TypeName = "UnityEngine.UI.CanvasScaler"},
                new CSTypeInfo() {TypeName = "UnityEngine.UI.ContentSizeFitter"},
                new CSTypeInfo() {TypeName = "UnityEngine.UI.GraphicRaycaster"},
                new CSTypeInfo() {TypeName = "UnityEngine.UI.GridLayoutGroup"},
                new CSTypeInfo() {TypeName = "UnityEngine.UI.Image"},
                new CSTypeInfo() {TypeName = "UnityEngine.UI.InputField"},
                new CSTypeInfo() {TypeName = "UnityEngine.UI.Scrollbar"},
                new CSTypeInfo() {TypeName = "UnityEngine.UI.ScrollRect"},
                new CSTypeInfo() {TypeName = "UnityEngine.UI.Slider"},
                new CSTypeInfo() {TypeName = "UnityEngine.UI.Text"},
                new CSTypeInfo() {TypeName = "UnityEngine.UI.Toggle"},
                new CSTypeInfo() {TypeName = "UnityEngine.UI.ToggleGroup"},
                new CSTypeInfo() {TypeName = "UnityEngine.EventSystems.UIBehaviour"},
            }
        },
        new CSharpInfo()
        {
            IsNone = true, IsCSTypeInfo = false, AssemblieName = "UnityEngine.UIModule",
            CSTypeInfoList = new List<CSTypeInfo>()
            {
                new CSTypeInfo(){TypeName = "UnityEngine.CanvasGroup"},
                new CSTypeInfo(){TypeName = "UnityEngine.RenderMode"},
                new CSTypeInfo(){TypeName = "UnityEngine.CanvasRenderer"},
                new CSTypeInfo(){TypeName = "UnityEngine.Canvas"},
            }
        },
        new CSharpInfo()
        {
            IsNone = true, IsCSTypeInfo = false, AssemblieName = "mscorlib",
            CSTypeInfoList = new List<CSTypeInfo>()
            {
                new CSTypeInfo() {TypeName = "System.GC"},
                new CSTypeInfo() {TypeName = "System.Object"},
                new CSTypeInfo() {TypeName = "System.String"},
                new CSTypeInfo() {TypeName = "System.IO.FileInfo"},
                new CSTypeInfo() {TypeName = "System.IO.DirectoryInfo"},
                new CSTypeInfo() {TypeName = "System.Security.AccessControl.AccessControlSections"},
                new CSTypeInfo() {TypeName = "System.Security.AccessControl.DirectorySecurity"},
                new CSTypeInfo() {TypeName = "System.Security.AccessControl.FileSecurity"},
            }
        },
        new CSharpInfo()
        {
            IsNone = true, IsCSTypeInfo = false, AssemblieName = "UnityEngine.InputLegacyModule",
            CSTypeInfoList = new List<CSTypeInfo>()
            {
                new CSTypeInfo(){TypeName = "UnityEngine.Input"},
                new CSTypeInfo(){TypeName = "UnityEngine.Touch"},
                new CSTypeInfo(){TypeName = "UnityEngine.TouchPhase"},
            }
        },
        new CSharpInfo()
        {
            IsNone = true, IsCSTypeInfo = false, AssemblieName = "UnityEngine.ParticleSystemModule",
            CSTypeInfoList = new List<CSTypeInfo>()
            {
                new CSTypeInfo(){TypeName = "UnityEngine.ParticleSystem"},
            }
        },
        new CSharpInfo()
        {
            IsNone = true, IsCSTypeInfo = false, AssemblieName = "UnityEngine.PhysicsModule",
            CSTypeInfoList = new List<CSTypeInfo>()
            {
                new CSTypeInfo(){TypeName = "UnityEngine.BoxCollider"},
                new CSTypeInfo(){TypeName = "UnityEngine.Collider"},
                new CSTypeInfo(){TypeName = "UnityEngine.Collision"},
                new CSTypeInfo(){TypeName = "UnityEngine.RaycastHit"},
                new CSTypeInfo(){TypeName = "UnityEngine.SphereCollider"},
                new CSTypeInfo(){TypeName = "UnityEngine.CharacterController"},
            }
        },
        new CSharpInfo()
        {
            IsNone = true, IsCSTypeInfo = false, AssemblieName = "UnityEngine.VideoModule",
            CSTypeInfoList = new List<CSTypeInfo>()
            {
                new CSTypeInfo(){TypeName = "UnityEngine.Video.VideoClip"},
                new CSTypeInfo(){TypeName = "UnityEngine.Video.VideoPlayer"},
                new CSTypeInfo(){TypeName = "UnityEngine.Video.VideoSource"},
            }
        },
        new CSharpInfo()
        {
            IsNone = true, IsCSTypeInfo = false, AssemblieName = "UnityEngine.AudioModule",
            CSTypeInfoList = new List<CSTypeInfo>()
            {
                new CSTypeInfo(){TypeName = "UnityEngine.AudioClip"},
                new CSTypeInfo(){TypeName = "UnityEngine.AudioSource"},
            }
        },
        new CSharpInfo()
        {
            IsNone = true, IsCSTypeInfo = false, AssemblieName = "UnityEngine.AnimationModule",
            CSTypeInfoList = new List<CSTypeInfo>()
            {
                new CSTypeInfo(){TypeName = "UnityEngine.Animation"},
                new CSTypeInfo(){TypeName = "UnityEngine.AnimationClip"},
                new CSTypeInfo(){TypeName = "UnityEngine.Animator"},
                new CSTypeInfo(){TypeName = "UnityEngine.AnimatorOverrideController"},
            }
        },
        new CSharpInfo()
        {
            IsNone = true, IsCSTypeInfo = false, AssemblieName = "UnityEngine.UnityWebRequestWWWModule",
            CSTypeInfoList = new List<CSTypeInfo>()
            {
                new CSTypeInfo(){TypeName = "UnityEngine.WWW"},
            }
        },
        new CSharpInfo()
        {
            IsNone = true, IsCSTypeInfo = false, AssemblieName = "System.Xml",
            CSTypeInfoList = new List<CSTypeInfo>()
            {
                new CSTypeInfo(){TypeName = "System.Xml.XmlNodeList"},
            }
        },
    };

    /// <summary>
    /// C# 类库
    /// </summary>
    [Serializable]
    public class CSharpInfo
    {
        /// <summary>
        /// 是否为空
        /// </summary>
        [HideInInspector] public bool IsNone = false;

        /// <summary>
        /// 是否有类型信息
        /// </summary>
        [HideInInspector] public bool IsCSTypeInfo = true;

        /// <summary>
        /// 类库名称
        /// </summary>
        [EnableIf("IsCSTypeInfo")]
        [BoxGroup("设置", ShowLabel = false)]
        [ValueDropdown("GetAllAssembly", FlattenTreeView = true, DoubleClickToConfirm = true)]
        [OnValueChanged("OnAssemblieChanged")]
        [HideLabel]
        public string AssemblieName = NONE;


        /// <summary>
        ///类库变化回调
        /// </summary>
        public void OnAssemblieChanged()
        {
            if (!AssemblieName.Equals(NONE) && !string.IsNullOrEmpty(AssemblieName))
            {
                IsNone = true;
            }
        }

        /// <summary>
        /// 获取所有类库
        /// </summary>
        /// <returns>返回选中类库</returns>
        private IEnumerable GetAllAssembly()
        {
            List<Assembly> Assemblies = Singleton.GetAllAssemblie();
            return Assemblies.Select(x => new ValueDropdownItem(x.GetName().Name, x.GetName().Name));
        }


        /// <summary>
        /// C# 类型信息数组（属于当前类库）
        /// </summary>
        [EnableIf("IsNone")]
        [BoxGroup("设置", ShowLabel = false)]
        [LabelText("TypeInfo")]
        [ListDrawerSettings(DraggableItems = false)]
        [OnValueChanged("OnCSTypeInfoChanged")]
        public List<CSTypeInfo> CSTypeInfoList = new List<CSTypeInfo>();

        /// <summary>
        /// 类型信息变化回调
        /// </summary>
        private void OnCSTypeInfoChanged()
        {
            IsCSTypeInfo = CSTypeInfoList.Count < 1;
            foreach (var typeInfo in CSTypeInfoList)
            {
                if (typeInfo.CurrAssemblyName.IsNullOrWhitespace())
                {
                    typeInfo.CurrAssemblyName = AssemblieName;
                }
            }
        }
    }

    /// <summary>
    /// C# 类型信息
    /// </summary>
    [GUIColor(0, 1f, 0f, 1f)]
    [Serializable]
    public class CSTypeInfo
    {
        /// <summary>
        /// 当前库
        /// </summary>
        [HideInInspector] public string CurrAssemblyName;

        /// <summary>
        /// 类型名称
        /// </summary>
        [BoxGroup("设置", ShowLabel = false)]
        [ValueDropdown("GetCurrAllType", FlattenTreeView = true, DoubleClickToConfirm = true)]
        [HideLabel]
        public string TypeName = NONE;


        /// <summary>
        /// 获取当前所有类型
        /// </summary>
        /// <returns></returns>
        protected IEnumerable GetCurrAllType()
        {
            List<Type> allType = Singleton.GetTypes(CurrAssemblyName);
            return allType.Select(x => new ValueDropdownItem(x.FullName, x.FullName));
        }
    }

    /// <summary>
    /// 空标签
    /// </summary>
    protected const string NONE = "None";

    /// <summary>
    /// 刷新所有类库信息（排序使用）
    /// </summary>
    public void RefreshCSharpInfo()
    {
        if (SirenixEditorGUI.ToolbarButton(EditorIcons.Refresh))
        {
            for (int i = 0; i < CSharpInfoList.Count; i++)
            {
                CSharpInfoList[i].CSTypeInfoList.Sort((PreValue, LaterValue) =>
                {
                    return Sort(PreValue.TypeName, LaterValue.TypeName);
                });
            }

            CSharpInfoList.Sort((PreValue, LaterValue) =>
            {
                return Sort(PreValue.AssemblieName, LaterValue.AssemblieName);
            });
        }
    }

    /// <summary>
    /// 排序
    /// </summary>
    /// <param name="PreValue"></param>
    /// <param name="LaterValue"></param>
    /// <returns></returns>
    protected int Sort(string PreValue, string LaterValue)
    {
        if (LaterValue.Equals(NONE))
        {
            return 1;
        }
        return PreValue.CompareTo(LaterValue);
    }

    /// <summary>
    /// 获取所有类库
    /// </summary>
    /// <returns></returns>
    public List<Assembly> GetAllAssemblie()
    {
        List<Assembly> Assemblies = new List<Assembly>();
        Assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies());

        foreach (var sharpInfo in CSharpInfoList)
        {
            if (!sharpInfo.AssemblieName.Equals(NONE))
            {
                Assembly assembly = GetAssemblie(sharpInfo.AssemblieName);
                if (assembly != null)
                {
                    Assemblies.Remove(assembly);
                }
            }
        }
        return Assemblies;
    }

    /// <summary>
    /// 获取类库
    /// </summary>
    /// <param name="AssemblieName"></param>
    /// <returns></returns>
    public static Assembly GetAssemblie(string AssemblieName)
    {
        if (!AssemblieName.IsNullOrWhitespace())
        {
            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            if (assemblies != null)
            {
                for (int i = assemblies.Length - 1; i >= 0; i--)
                {
                    string assemblieName = assemblies[i].GetName().Name;
                    if (assemblieName.Equals(AssemblieName))
                    {
                        return assemblies[i];
                    }
                }
            }
        }
        return null;
    }

    /// <summary>
    /// 设置所有类型信息
    /// </summary>
    /// <param name="kay"></param>Dic
    /// <param name="csharpInfo"></param>
    public CSharpInfo GetCSharpInfo(string assemblyName)
    {
        foreach (var sharpInfo in CSharpInfoList)
        {
            if (sharpInfo.IsNone && sharpInfo.AssemblieName.Equals(assemblyName))
            {
                return sharpInfo;
            }
        }
        return null;
    }

    /// <summary>
    /// 获取当前所有类库名称
    /// </summary>
    /// <returns></returns>
    public List<string> GetCurrAllCSTypeName()
    {
        List<string> currAllCSTypeName = new List<string>();
        foreach (var sharpInfo in CSharpInfoList)
        {
            if (sharpInfo.IsNone)
            {
                foreach (var typeInfo in sharpInfo.CSTypeInfoList)
                {
                    if (!typeInfo.TypeName.IsNullOrWhitespace())
                    {
                        currAllCSTypeName.Add(typeInfo.TypeName);
                    }
                }
            }
        }
        return currAllCSTypeName;
    }

    /// <summary>
    /// 获取当前所有类型 
    /// </summary>
    /// <returns></returns>
    private List<Type> GetCurrAllType()
    {
        List<Type> types = new List<Type>();
        foreach (var sharpInfo in CSharpInfoList)
        {
            if (sharpInfo.IsNone)
            {
                foreach (var typeInfo in sharpInfo.CSTypeInfoList)
                {
                    if (!typeInfo.TypeName.IsNullOrWhitespace())
                    {
                        Type type = GetCSType(sharpInfo.AssemblieName, typeInfo.TypeName);
                        if (type != null)
                        {
                            types.Add(type);
                        }
                    }
                }
            }
        }
        return types;
    }

    /// <summary>
    ///获取C#类型
    /// </summary>
    /// <param name="assembly"></param>
    /// <param name="typeName"></param>
    /// <returns></returns>
    private Type GetCSType(string assemblyName, string typeName)
    {
        Assembly assembly = GetAssemblie(assemblyName);
        if (assembly != null)
        {
            Type[] typeArray = assembly.GetTypes();
            if (typeArray != null)
            {
                foreach (var ty in typeArray)
                {
                    if (ty.FullName.Equals(typeName))
                    {
                        return ty;
                    }
                }
            }
        }
        return null;
    }

    /// <summary>
    /// 获取C#类型
    /// </summary>
    /// <param name="typeName"></param>
    /// <returns></returns>
    private Type GetCSType(string typeName)
    {
        foreach (var sharpInfo in CSharpInfoList)
        {
            if (sharpInfo.IsNone)
            {
                foreach (var csTypeInfo in sharpInfo.CSTypeInfoList)
                {
                    if (csTypeInfo.TypeName.Equals(typeName))
                    {
                        return GetCSType(sharpInfo.AssemblieName, csTypeInfo.TypeName);
                    }
                }
            }
        }
        return null;
    }

    /// <summary>
    /// 获取类库中类型
    /// </summary>
    /// <param name="assembly"></param>
    /// <returns></returns>
    public List<Type> GetTypes(string assemblyName)
    {
        List<Type> typeList = new List<Type>();
        Assembly assembly = GetAssemblie(assemblyName);
        if (assembly != null)
        {
            typeList.AddRange(assembly.GetTypes());
            CSharpInfo TempCSharpInfo = GetCSharpInfo(assemblyName);
            if (TempCSharpInfo != null)
            {
                foreach (var typeInfo in TempCSharpInfo.CSTypeInfoList)
                {
                    if (!typeInfo.TypeName.Equals(NONE))
                    {
                        int len = typeList.Count;
                        for (int i = len - 1; i >= 0; i--)
                        {
                            string typeName = typeList[i].FullName;
                            if (typeInfo.TypeName.Equals(typeName))
                            {
                                typeList.Remove(typeList[i]);
                                break;
                            }
                        }
                    }
                }
            }
        }
        return typeList;
    }
}